/*
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 * openUBMC is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *         http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

#include <gtest/gtest.h>

#include <ipmb/ipmb.h>
#include <mc/engine/service.h>
#include <mc/variant.h>
#include <mc/common.h>
#include <test_utilities/test_base.h>

#include <memory>
#include <vector>

namespace test_ipmb {

class test_interface : public mc::engine::interface<test_interface> {
public:
    MC_INTERFACE("bmc.kepler.IpmiCore")

    //a{ss}yyyyyay
    mc::variant Request(
        const mc::dict& ctx,              // a{ss} - 上下文字典
        uint8_t channel_type,              // y - 通道类型
        uint8_t instance,                  // y - 实例序号
        uint8_t net_fn,                   // y - 网络功能码
        uint8_t lun,                      // y - 逻辑单元号
        uint8_t cmd,                      // y - 命令字
        const std::vector<uint8_t>& data  // ay - 命令参数数据
    ) {
        ilog("test_ipmb_interface: Request");
        mc::variants result = {mc::variant(0), mc::variant(std::vector<uint8_t>{0x00, 0x01, 0x02})};
        return mc::variant(result);
    }
};

class test_object : public mc::engine::object<test_object> {
public:
    MC_OBJECT(test_object, "bmc.kepler.IpmiCore", "/bmc/kepler/IpmiCore", (test_interface))

    test_interface m_test_interface;
};

class test_service : public mc::engine::service {
public:
    test_service(const std::string& name) : mc::engine::service(name) {
    }
};

class ipmb_test : public mc::test::TestWithEngine {
protected:

    static void SetUpTestSuite() {
        TestWithEngine::SetUpTestSuite();
        m_service.init();
        m_service.start();
        m_obj = test_object::create();
        m_obj->set_object_path("/bmc/kepler/IpmiCore");
        m_obj->set_object_name("bmc.kepler.IpmiCore");
        m_service.register_object(m_obj);
    }

    static void TearDownTestSuite() {
        TestWithEngine::TearDownTestSuite();
    }

    void SetUp() override {
        m_ipmb = std::make_unique<mc::ipmb>(&m_service);
    }

    void TearDown() override {
        m_ipmb.reset();
    }

    static test_service m_service;
    static mc::shared_ptr<test_object> m_obj;
    std::unique_ptr<mc::ipmb> m_ipmb;
};

test_service ipmb_test::m_service{"bmc.kepler.ipmi_core"};
mc::shared_ptr<test_object> ipmb_test::m_obj;
} // namespace test_ipmb

// 添加反射元数据定义（必须在命名空间外）
MC_REFLECT(test_ipmb::test_interface, (Request))
MC_REFLECT(test_ipmb::test_object, ((m_test_interface, "bmc.kepler.IpmiCore")))

using namespace test_ipmb;

TEST_F(ipmb_test, construct_with_valid_service) {
    EXPECT_NE(m_ipmb, nullptr);
    EXPECT_THROW(mc::ipmb(nullptr), mc::invalid_argument_exception);
}


TEST_F(ipmb_test, parse_response_supports_array_payload) {
    mc::variant completion_code = static_cast<int64_t>(0xC0);
    mc::variant payload         = std::vector<uint8_t>{0x11, 0x22};

    auto parsed = m_ipmb->parse_response(completion_code, payload);

    ASSERT_TRUE(parsed.has_value());
    EXPECT_EQ(parsed->completion_code, mc::ipmi_completion_code::node_busy);
    EXPECT_EQ(parsed->data, (std::vector<uint8_t>{0x11, 0x22}));
}

TEST_F(ipmb_test, parse_response_supports_string_payload) {
    mc::variant completion_code = static_cast<int64_t>(0x00);
    mc::variant payload         = std::string("OK");

    auto parsed = m_ipmb->parse_response(completion_code, payload);

    ASSERT_TRUE(parsed.has_value());
    EXPECT_EQ(parsed->data, (std::vector<uint8_t>{'O', 'K'}));
}

TEST_F(ipmb_test, parse_response_rejects_invalid_completion_type) {
    mc::variant completion_code = std::string("bad");
    mc::variant payload         = std::vector<uint8_t>{0x01};

    auto parsed = m_ipmb->parse_response(completion_code, payload);
    EXPECT_FALSE(parsed.has_value());
}

TEST_F(ipmb_test, parse_response_rejects_non_integer_item) {
    mc::variant  completion_code = static_cast<int64_t>(0x00);
    mc::variants invalid_payload{std::string("bad")};

    auto parsed = m_ipmb->parse_response(completion_code, mc::variant(invalid_payload));
    EXPECT_FALSE(parsed.has_value());
}

TEST_F(ipmb_test, parse_response_rejects_unsupported_type) {
    mc::variant completion_code = static_cast<int64_t>(0x00);
    mc::variant payload         = true;

    auto parsed = m_ipmb->parse_response(completion_code, payload);
    EXPECT_FALSE(parsed.has_value());
}

TEST_F(ipmb_test, format_completion_code_covers_known_values) {
    EXPECT_EQ(mc::ipmi_utils::format_completion_code(mc::ipmi_completion_code::success), "Success");
    EXPECT_EQ(mc::ipmi_utils::format_completion_code(mc::ipmi_completion_code::timeout), "Timeout");
    auto unknown = static_cast<mc::ipmi_completion_code>(0xAB);
    EXPECT_EQ(mc::ipmi_utils::format_completion_code(unknown), "Unknown Completion Code");
}

TEST_F(ipmb_test, retry_count_is_clamped) {
    EXPECT_EQ(m_ipmb->get_retry_count(), 1);
    m_ipmb->set_retry_count(3);
    EXPECT_EQ(m_ipmb->get_retry_count(), 3);
    m_ipmb->set_retry_count(-5);
    EXPECT_EQ(m_ipmb->get_retry_count(), 0);
}

TEST_F(ipmb_test, is_success_and_retryable_helpers) {
    EXPECT_TRUE(mc::ipmi_utils::is_success(mc::ipmi_completion_code::success));
    EXPECT_FALSE(mc::ipmi_utils::is_success(mc::ipmi_completion_code::node_busy));
    EXPECT_TRUE(mc::ipmi_utils::is_retryable(mc::ipmi_completion_code::node_busy));
    EXPECT_FALSE(mc::ipmi_utils::is_retryable(mc::ipmi_completion_code::invalid_command));
}

TEST_F(ipmb_test, parse_response_with_empty_array_payload) {
    mc::variant completion_code = static_cast<int64_t>(0x00);
    mc::variants empty_payload;
    mc::variant payload = mc::variant(empty_payload);

    auto parsed = m_ipmb->parse_response(completion_code, payload);

    ASSERT_TRUE(parsed.has_value());
    EXPECT_EQ(parsed->completion_code, mc::ipmi_completion_code::success);
    EXPECT_TRUE(parsed->data.empty());
}

TEST_F(ipmb_test, parse_response_with_large_array_payload) {
    std::vector<uint8_t> large_data(256);
    for (size_t i = 0; i < large_data.size(); ++i) {
        large_data[i] = static_cast<uint8_t>(i);
    }

    mc::variant completion_code = static_cast<int64_t>(0x00);
    mc::variant payload         = large_data;

    auto parsed = m_ipmb->parse_response(completion_code, payload);

    ASSERT_TRUE(parsed.has_value());
    EXPECT_EQ(parsed->completion_code, mc::ipmi_completion_code::success);
    EXPECT_EQ(parsed->data.size(), 256);
    EXPECT_EQ(parsed->data, large_data);
}

TEST_F(ipmb_test, parse_response_with_empty_string_payload) {
    mc::variant completion_code = static_cast<int64_t>(0x00);
    mc::variant payload         = std::string("");

    auto parsed = m_ipmb->parse_response(completion_code, payload);

    ASSERT_TRUE(parsed.has_value());
    EXPECT_EQ(parsed->completion_code, mc::ipmi_completion_code::success);
    EXPECT_TRUE(parsed->data.empty());
}

TEST_F(ipmb_test, format_completion_code_all_values) {
    // 测试所有已知的完成码
    EXPECT_EQ(mc::ipmi_utils::format_completion_code(mc::ipmi_completion_code::success), "Success");
    EXPECT_EQ(mc::ipmi_utils::format_completion_code(mc::ipmi_completion_code::node_busy), "Node Busy");
    EXPECT_EQ(mc::ipmi_utils::format_completion_code(mc::ipmi_completion_code::invalid_command), "Invalid Command");
    EXPECT_EQ(mc::ipmi_utils::format_completion_code(mc::ipmi_completion_code::invalid_command_for_lun), "Invalid Command for LUN");
    EXPECT_EQ(mc::ipmi_utils::format_completion_code(mc::ipmi_completion_code::timeout), "Timeout");
    EXPECT_EQ(mc::ipmi_utils::format_completion_code(mc::ipmi_completion_code::out_of_space), "Out of Space");
    EXPECT_EQ(mc::ipmi_utils::format_completion_code(mc::ipmi_completion_code::invalid_reservation), "Invalid Reservation");
    EXPECT_EQ(mc::ipmi_utils::format_completion_code(mc::ipmi_completion_code::data_truncated), "Data Truncated");
    EXPECT_EQ(mc::ipmi_utils::format_completion_code(mc::ipmi_completion_code::invalid_length), "Invalid Length");
    EXPECT_EQ(mc::ipmi_utils::format_completion_code(mc::ipmi_completion_code::length_exceeded), "Length Exceeded");
    EXPECT_EQ(mc::ipmi_utils::format_completion_code(mc::ipmi_completion_code::parameter_out_of_range), "Parameter Out of Range");
    EXPECT_EQ(mc::ipmi_utils::format_completion_code(mc::ipmi_completion_code::cannot_return_data), "Cannot Return Data");
    EXPECT_EQ(mc::ipmi_utils::format_completion_code(mc::ipmi_completion_code::req_data_not_present), "Request Data Not Present");
    EXPECT_EQ(mc::ipmi_utils::format_completion_code(mc::ipmi_completion_code::invalid_data_field), "Invalid Data Field");
    EXPECT_EQ(mc::ipmi_utils::format_completion_code(mc::ipmi_completion_code::command_illegal), "Command Illegal");
    EXPECT_EQ(mc::ipmi_utils::format_completion_code(mc::ipmi_completion_code::response_not_provided), "Response Not Provided");
    EXPECT_EQ(mc::ipmi_utils::format_completion_code(mc::ipmi_completion_code::duplicated_request), "Duplicated Request");
    EXPECT_EQ(mc::ipmi_utils::format_completion_code(mc::ipmi_completion_code::unknown_error), "Unknown Error");
}

TEST_F(ipmb_test, retry_count_boundary_values) {
    // 测试边界值
    EXPECT_EQ(m_ipmb->get_retry_count(), 1);
    
    m_ipmb->set_retry_count(0);
    EXPECT_EQ(m_ipmb->get_retry_count(), 0);
    
    m_ipmb->set_retry_count(10);
    EXPECT_EQ(m_ipmb->get_retry_count(), 10);
    
    m_ipmb->set_retry_count(-1);
    EXPECT_EQ(m_ipmb->get_retry_count(), 0);
    
    m_ipmb->set_retry_count(100);
    EXPECT_EQ(m_ipmb->get_retry_count(), 100);
}

TEST_F(ipmb_test, destructor_does_not_crash) {
    // m_service 应该为指针类型，直接解引用获取对象引用，避免非法成员调用
    // 检查 ipmb 析构不会崩溃
    {
        mc::ipmb local_ipmb(&m_service);
    }
    // 析构函数应该正常执行，不应该崩溃
    EXPECT_TRUE(true);
}

TEST_F(ipmb_test, send_request_with_valid_parameters) {
    // 测试 send_request 基本功能
    // 注意：这个测试依赖于真实的 service，如果 service 不可用，测试可能会失败
    // send_request 内部会调用 send_to_ipmi_core，因此这个测试也间接测试了 send_to_ipmi_core
    mc::ipmi_request request;
    request.net_fn     = mc::ipmi_net_fn::app;
    request.cmd         = 0x01;
    request.data        = {0x01, 0x02, 0x03};
    request.timeout_ms  = 5000;

    auto response = m_ipmb->send_request(mc::ipmb_channel_type::me, request);
    // 由于无法 mock service，这里只验证函数调用不会崩溃
    // 实际返回值取决于测试环境
    // 如果 service 可用，response 可能有值；如果不可用，response 为 nullopt
    EXPECT_TRUE(true);
}

TEST_F(ipmb_test, send_request_with_empty_data) {
    // 测试 send_request 使用空数据
    mc::ipmi_request request;
    request.net_fn     = mc::ipmi_net_fn::chassis;
    request.cmd         = 0x01;
    request.data        = {};
    request.timeout_ms  = 5000;

    auto response = m_ipmb->send_request(mc::ipmb_channel_type::me, request);
    // 验证函数调用不会崩溃
    EXPECT_TRUE(true);
}

TEST_F(ipmb_test, send_request_with_different_channels) {
    // 测试 send_request 使用不同的通道类型
    mc::ipmi_request request;
    request.net_fn     = mc::ipmi_net_fn::oem;
    request.cmd         = 0x44;
    request.data        = {0x01};
    request.timeout_ms  = 5000;

    // 测试不同的通道类型
    auto response1 = m_ipmb->send_request(mc::ipmb_channel_type::me, request);
    auto response2 = m_ipmb->send_request(mc::ipmb_channel_type::host, request);
    auto response3 = m_ipmb->send_request(mc::ipmb_channel_type::lan, request);
    
    // 验证函数调用不会崩溃
    EXPECT_TRUE(true);
}

TEST_F(ipmb_test, send_request_with_different_net_fn) {
    // 测试 send_request 使用不同的网络功能码
    std::vector<uint8_t> test_data = {0x01, 0x02};

    auto response1 = m_ipmb->send_request(mc::ipmb_channel_type::me, mc::ipmi_net_fn::chassis, 0x01, test_data);
    auto response2 = m_ipmb->send_request(mc::ipmb_channel_type::me, mc::ipmi_net_fn::app, 0x01, test_data);
    auto response3 = m_ipmb->send_request(mc::ipmb_channel_type::me, mc::ipmi_net_fn::oem, 0x44, test_data);
    
    // 验证函数调用不会崩溃
    EXPECT_TRUE(true);
}

TEST_F(ipmb_test, send_request_with_custom_timeout) {
    // 测试 send_request 使用自定义超时时间
    mc::ipmi_request request;
    request.net_fn     = mc::ipmi_net_fn::app;
    request.cmd         = 0x01;
    request.data        = {0x01};
    request.timeout_ms  = 1000; // 1秒超时

    auto response = m_ipmb->send_request(mc::ipmb_channel_type::me, request);
    // 验证函数调用不会崩溃
    EXPECT_TRUE(true);
}

TEST_F(ipmb_test, send_request_with_retry_mechanism) {
    // 测试 send_request 的重试机制
    m_ipmb->set_retry_count(2);
    
    mc::ipmi_request request;
    request.net_fn     = mc::ipmi_net_fn::app;
    request.cmd         = 0x01;
    request.data        = {0x01};
    request.timeout_ms  = 5000;

    auto response = m_ipmb->send_request(mc::ipmb_channel_type::me, request);
    // 验证函数调用不会崩溃，重试机制应该正常工作
    EXPECT_TRUE(true);
}

TEST_F(ipmb_test, send_request_overload_with_parameters) {
    // 测试 send_request 的重载版本（直接传参数）
    std::vector<uint8_t> test_data = {0x01, 0x02, 0x03};
    
    auto response = m_ipmb->send_request(mc::ipmb_channel_type::me, mc::ipmi_net_fn::app, 0x01, test_data, 5000);
    // 验证函数调用不会崩溃
    EXPECT_TRUE(true);
}

TEST_F(ipmb_test, send_request_overload_with_default_timeout) {
    // 测试 send_request 的重载版本（使用默认超时时间）
    std::vector<uint8_t> test_data = {0x01};
    
    auto response = m_ipmb->send_request(mc::ipmb_channel_type::me, mc::ipmi_net_fn::chassis, 0x01, test_data);
    // 验证函数调用不会崩溃，应该使用默认超时时间（5000ms）
    EXPECT_TRUE(true);
}

TEST_F(ipmb_test, send_request_overload_with_empty_data) {
    // 测试 send_request 的重载版本（空数据）
    auto response = m_ipmb->send_request(mc::ipmb_channel_type::me, mc::ipmi_net_fn::app, 0x01);
    // 验证函数调用不会崩溃，应该使用默认空数据
    EXPECT_TRUE(true);
}

TEST_F(ipmb_test, send_request_handles_large_data) {
    // 测试 send_request 处理大量数据
    std::vector<uint8_t> large_data(1024);
    for (size_t i = 0; i < large_data.size(); ++i) {
        large_data[i] = static_cast<uint8_t>(i & 0xFF);
    }

    mc::ipmi_request request;
    request.net_fn     = mc::ipmi_net_fn::oem;
    request.cmd         = 0x44;
    request.data        = large_data;
    request.timeout_ms  = 5000;

    auto response = m_ipmb->send_request(mc::ipmb_channel_type::me, request);
    // 验证函数调用不会崩溃
    EXPECT_TRUE(true);
}
